package com.vn.ld.btc.dao.util;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import com.vn.ld.btc.dao.common.SearchItem;
import com.vn.ld.common.domain.PageObjInfo;

/**
 * QueryBuilderUtil
 * 
 * @author Shark{loi.do.duy}
 */
public class QueryBuilderUtil {

	/**
	 * Create QueryObject
	 * 
	 * @param entityManager
	 * @param queryString
	 * @param orderClause
	 * @param whereClause
	 * @param listSearchItems
	 * @return
	 */
	public static Query createQuery(EntityManager entityManager, String queryString, String orderClause, String whereClause, List<SearchItem> listSearchItems) {
		String sqlQuery = getQueryString(queryString, orderClause, whereClause, listSearchItems);
		Query query = null;
		if (sqlQuery != null) {
			query = entityManager.createQuery(sqlQuery);
			if (listSearchItems != null && listSearchItems.size() > 0) {
				for (SearchItem item : listSearchItems) {
					query.setParameter(item.getKey(), item.getValue());
				}
			}
		}
		return query;
	}

	/**
	 * Create query object
	 * 
	 * @param entityManager
	 * @param queryString
	 * @param orderClause
	 * @param whereClause
	 * @param pagerObj
	 * @param mapParam
	 * @param entity
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "static-access", "unchecked" })
	public static Query createQuery(EntityManager entityManager, String queryString, String orderClause, String whereClause, PageObjInfo pagerObj,
			Map<String, Object> mapParam, Class entity) {
		Integer startRecord = 0;
		Integer endRecord = 0;

		if (pagerObj == null) {
			startRecord = pagerObj.DEFAULT_SQL_INDEX;
			endRecord = pagerObj.DEAULT_OFFSET;
		} else {
			startRecord = (pagerObj.getIndex() - 1) * pagerObj.getOffset();
			endRecord = pagerObj.getIndexPage() * pagerObj.getOffset();
		}

		String sqlQuery = createQueryString(queryString, orderClause, whereClause, startRecord, endRecord);

		Query query = entityManager.createNamedQuery(sqlQuery, entity);

		if (mapParam != null && mapParam.size() > 0) {
			for (String key : mapParam.keySet()) {
				query.setParameter(key, mapParam.get(key));
			}
		}
		return query;
	}

	/**
	 * @param entityManager
	 * @param queryString
	 * @param pageObjInfo
	 * @param mapParams
	 * @param entity
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "static-access", "unchecked" })
	public static Query createQuery(EntityManager entityManager, String queryString, PageObjInfo pageObjInfo, Map<String, Object> mapParams, Class entity) {
		Integer startRecord = 0;
		Integer endRecord = 0;

		if (pageObjInfo == null) {
			startRecord = pageObjInfo.DEFAULT_SQL_INDEX;
			endRecord = pageObjInfo.DEAULT_OFFSET;
		} else {
			startRecord = (pageObjInfo.getIndexPage() - 1) * pageObjInfo.getOffset();
			endRecord = pageObjInfo.getIndexPage() * pageObjInfo.getOffset();
		}

		String queryCreate = createQueryString(queryString, startRecord, endRecord);

		Query query = entityManager.createQuery(queryCreate, entity);

		if (mapParams != null && mapParams.size() > 0) {
			for (String key : mapParams.keySet()) {
				query.setParameter(key, mapParams.get(key));
			}
		}

		return query;
	}

	/**
	 * Create query count object
	 * 
	 * @param entityManager
	 * @param queryStr
	 * @param orderStr
	 * @param mapParametere
	 * @return
	 */
	public static Query createCountQuery(EntityManager entityManager, String queryStr, String orderStr, final Map<String, Object> mapParameter) {
		String countQuery = createCountQueryStr(queryStr, orderStr);

		Query query = entityManager.createQuery(countQuery);

		if (mapParameter != null && mapParameter.size() > 0) {
			for (String key : mapParameter.keySet()) {
				query.setParameter(key, mapParameter.get(key));
			}
		}
		return query;
	}

	/**
	 * Create query count
	 * 
	 * @param entityManager
	 * @param queryStr
	 * @param orderStr
	 * @param searchItems
	 * @return
	 */
	public static Query createCountQuery(EntityManager entityManager, String queryStr, String whereStr, List<SearchItem> searchItems) {
		String countQuery = createCountQueryStr(queryStr, whereStr);

		Query query = entityManager.createQuery(countQuery);

		if (searchItems != null && searchItems.size() > 0) {
			for (SearchItem item : searchItems) {
				query.setParameter(item.getKey(), item.getValue());
			}
		}

		return query;
	}

	/**
	 * @param entityManager
	 * @param queryStr
	 * @return
	 */
	public static Query createCountQuery(EntityManager entityManager, String queryStr) {
		String countQuery = createCountQueryStr(queryStr);

		return entityManager.createQuery(countQuery);
	}

	/**
	 * Get QueryString
	 * 
	 * @param queryString
	 * @param orderClause
	 * @param whereClause
	 * @param listSearchItems
	 * @return
	 */
	public static String getQueryString(String queryString, String orderClause, String whereClause, List<SearchItem> listSearchItems) {
		final StringBuffer whereBuff = new StringBuffer();
		if (listSearchItems != null && listSearchItems.size() > 0) {
			for (SearchItem item : listSearchItems) {
				if (item.getLogicOperator() != null && item.getExpression() != null && item.getExpression().length() != 0) {
					if (item.isEnableNullSearch()) {
						whereBuff.append(" " + item.getLogicOperator() + " " + item.getExpression() + " ");
					} else {
						if (!item.isEmpty()) {
							whereBuff.append(" " + item.getLogicOperator() + " " + item.getExpression() + " ");
						}
					}
				}
			}
		}

		if (whereClause != null && whereClause.trim().length() != 0) {
			whereBuff.insert(0, whereClause);
			whereBuff.insert(0, " WHERE ");
		} else {
			if (whereBuff.length() > 0) {
				whereBuff.replace(0, 4, " WHERE ");
			}
		}

		final StringBuffer buffOrder = new StringBuffer();
		if (orderClause != null && orderClause.trim().length() != 0) {
			buffOrder.append(" ORDER BY ");
			buffOrder.append(orderClause);
		}
		return new StringBuffer(queryString).append(whereBuff).append(buffOrder).toString();
	}

	/**
	 * Create query string
	 * 
	 * @param queryString
	 * @param orderClause
	 * @param whereClause
	 * @param startRecord
	 * @param endRecord
	 * @return
	 */
	public static String createQueryString(String queryString, String orderClause, String whereClause, Integer startRecord, Integer offset) {
		final StringBuffer sqlQuery = new StringBuffer();
		sqlQuery.append(queryString);

		if (!whereClause.isEmpty()) {
			sqlQuery.append(" WHERE ");
			sqlQuery.append(whereClause);
		}

		if (!orderClause.isEmpty()) {
			sqlQuery.append(orderClause);
		}

		if (startRecord != null && offset != null) {
			sqlQuery.append(" LIMIT " + startRecord + "," + offset + " ");
		}

		return sqlQuery.toString();
	}

	/**
	 * @param queryString
	 * @param startRecord
	 * @param offset
	 * @return
	 */
	public static String createQueryString(String queryString, Integer startRecord, Integer offset) {
		final StringBuffer buffer = new StringBuffer();
		buffer.append(queryString);

		if (startRecord != null && offset != null) {
			buffer.append(" LIMIT " + startRecord + "," + offset + " ");
		}
		return buffer.toString();
	}

	/**
	 * @param query
	 * @param objInfo
	 */
	public static void addPagging(Query query, PageObjInfo objInfo) {
		if (query != null && objInfo != null) {
			query.setFirstResult(objInfo.getIndex());
			query.setMaxResults(objInfo.getOffset());
		}
	}

	/**
	 * @param pageObj
	 * @param objTotal
	 */
	public static void setTotalValue(PageObjInfo pageObj, Object objTotal) {
		if (pageObj != null && objTotal != null) {
			if (objTotal instanceof Long) {
				pageObj.setTotal(((Long) objTotal).longValue());
			} else if (objTotal instanceof Integer) {
				pageObj.setTotal(((Integer) objTotal).longValue());
			} else if (objTotal instanceof BigInteger) {
				pageObj.setTotal(((BigInteger) objTotal).longValue());
			} else if (objTotal instanceof BigDecimal) {
				pageObj.setTotal(((BigDecimal) objTotal).longValue());
			}
		}
	}

	/**
	 * Create count query string
	 * 
	 * @param queryStr
	 * @param sqlWhere
	 * @return
	 */
	public static String createCountQueryStr(String queryStr, String sqlWhere) {
		final StringBuffer queryCount = new StringBuffer();
		if (queryStr != null) {
			queryCount.append(queryStr);

			if (!sqlWhere.isEmpty()) {
				queryCount.append(" WHERE ");
				queryCount.append(sqlWhere);
			}
		}

		return queryCount.toString();
	}

	/**
	 * Create count query string
	 * 
	 * @param queryString
	 * @return
	 */
	public static String createCountQueryStr(String queryString) {
		return queryString;
	}

}
